import { commonApi } from '@/common/api/commonApi.js'
import _ from 'lodash'

export const EventName = {
  zoomend: 'zoomend',
  moveend: 'moveend',
  dragend: 'dragend',
  resize: 'resize',
  moving: 'moving',
  dragging: 'dragging',
  updatePosition: 'updatePosition',
  openInfoWindow: 'openInfoWindow',
  closeInfoWindow: 'closeInfoWindow',
  updateCenter: 'updateCenter'
}

export const ComponentName = {
  map: 'mx-map',
  marker: 'mx-marker',
  layer: 'mx-layer',
  info: 'mx-info'
}

function broadcast(componentName, eventName, params) {
  this.$children.forEach(child => {
    let name = child.$options.componentName
    if (name === componentName) {
      child.$emit.apply(child, [eventName].concat(params))
    } else {
      broadcast.apply(child, [componentName, eventName].concat([params]))
    }
  })
}

function getTriangleArea(p0, p1, p2) {
  let area = 0.0;
  area = p0[0] * p1[1] + p1[0] * p2[1] + p2[0] * p0[1] - p1[0] * p0[1] - p2[0] * p1[1] - p0[0] * p2[1];
  return area / 2;
}

export function GetPolygonAreaCenter(points) {
  points = points.map(v => ([parseFloat(v[0]), parseFloat(v[1])]))
  let sum_x = 0;
  let sum_y = 0;
  let sum_area = 0;
  let p0 = points[0]
  let p1 = points[1];
  let p2 = null
  let area = 0.0
  for (let i = 2; i < points.length; i++) {
    p2 = points[i];
    area = getTriangleArea(p0, p1, p2);
    sum_area += area;
    sum_x += (p0[0] + p1[0] + p2[0]) * area;
    sum_y += (p0[1] + p1[1] + p2[1]) * area;
    p1 = p2;
  }
  let xx = sum_x / sum_area / 3;
  let yy = sum_y / sum_area / 3;
  return [xx, yy]
}

export const Emitter = {
  methods: {
    dispatch(componentName, eventName, params) {
      let parent = this.$parent || this.$root
      let name = parent.$options.componentName

      while (parent && (!name || name !== componentName)) {
        parent = parent.$parent
        if (parent) {
          name = parent.$options.componentName
        }
      }
      if (parent) {
        parent.$emit.apply(parent, [eventName].concat(params))
      }
    },
    broadcast(componentName, eventName, params) {
      broadcast.call(this, componentName, eventName, params)
    }
  }
}

export class MergeRequest {
  constructor() {
    this.cacheObj = {}
  }

  run(name, fn) {
    return new Promise((resolve, reject) => {
      if (!this.cacheObj[name]) {
        this.cacheObj[name] = []
        this.cacheObj[name].push([resolve, reject])
        fn
          .then(res => {
            this.cacheObj[name].forEach(([resolve, reject]) => resolve && resolve(res))
          })
          .catch(e => {
            this.cacheObj[name].forEach(([resolve, reject]) => reject && reject(e))
          })
          .then(() => {
            this.cacheObj[name] = null
          })
      } else {
        this.cacheObj[name].push([resolve, reject])
      }
    })
  }
}

export default {
  async getSource(name, source) {
    let results = await this.case(source)
      .string(val => {
        return commonApi.dictionary(val)
      })
      .array(val => {
        return commonApi.dictionaries(val)
      })
      .object(val => {
        if (val.collectionName) {
          return commonApi.search(val.collectionName, val.options)
        } else if (val.runCloud) {
          return commonApi.runCloud(val.runCloud, val.options)
        }
      })
      .function(val => val)
      .default()
    results = source.formatter ? source.formatter(results) : results
    return { [name]: results }
  },

  case(value) {
    return {
      result: null,
      string(callback) {
        if (typeof value === 'string') {
          this.result = callback ? callback(value) : value
        }
        return this
      },
      number(callback) {
        if (typeof value === 'number') {
          this.result = callback ? callback(value) : value
        }
        return this
      },
      boolean(callback) {
        if (typeof value === 'boolean') {
          this.result = callback ? callback(value) : value
        }
        return this
      },
      function(callback) {
        if (typeof value === 'function') {
          this.result = callback ? callback(value) : value
        }
        return this
      },
      array(callback) {
        if (value instanceof Array) {
          this.result = callback ? callback(value) : value
        }
        return this
      },
      object(callback) {
        if (value instanceof Array || value === null || value === undefined || typeof value !== 'object') {
          return this
        }
        this.result = callback ? callback(value) : value
        return this
      },
      default(defaultValue) {
        if (this.result === null || this.result === undefined) {
          return defaultValue
        }
        return this.result
      }
    }
  },

  liveQuery(collectionName, options) {
    return commonApi.liveQuery(collectionName, options)
  }
}
